// SysIndex.h header file for SysIndex files

#include<iostream>
#include<string>
#include<fstream>
#include<iomanip>
#include<cstring>

#include"globalDBEngine.h"

#define CURSYSINDSIZEPTR (NEXTPTR-sizeof(int))
#define REMSYSINDSIZEPTR (CURSYSINDSIZEPTR-sizeof(int))
#define SYSINDEXENTRYPTR (REMSYSINDSIZEPTR-sizeof(long))
#define SYSINDNOEPTR (SYSINDEXENTRYPTR-sizeof(int))

#define SYSINDEXMETADATASIZE (sizeof(int)+sizeof(short)+sizeof(int)+sizeof(int)+sizeof(int)+sizeof(long)+sizeof(int))
#define SYSINDEXENTRYSPACE PAGESIZE-(SYSINDEXMETADATASIZE)
#define SYSINDEXENTRYSIZE (64+64+64+sizeof(char)+sizeof(short)+sizeof(short)+sizeof(int)+sizeof(int)+sizeof(char)+sizeof(char)+256+sizeof(int))

#define FIRSTSYSINDSLOTPTR (SYSINDNOEPTR-sizeof(char))
#define SYSINDSLOTSIZE (sizeof(char))

#define SYSINDINDEXNAMEPTR 0
#define SYSINDDBNAMEPTR (SYSINDINDEXNAMEPTR+64)
#define SYSINDTABLENAMEPTR (SYSINDDBNAMEPTR+64)
#define SYSINDUNIQRULEPTR (SYSINDTABLENAMEPTR+64)
#define SYSINDCOLCOUNTPTR (SYSINDUNIQRULEPTR+sizeof(char))
#define SYSINDFANOUTNOPTR (SYSINDCOLCOUNTPTR+sizeof(short))
#define SYSINDINDEXPAGEIDPTR (SYSINDFANOUTNOPTR+sizeof(short))
#define SYSINDPAGESIZEPTR (SYSINDINDEXPAGEIDPTR+sizeof(int))
#define SYSINDERASERULEPTR (SYSINDPAGESIZEPTR+sizeof(int))
#define SYSINDCLOSERULEPTR (SYSINDERASERULEPTR+sizeof(char))
#define SYSINDREMARKSPTR (SYSINDCLOSERULEPTR+sizeof(char))
#define SYSINDAVGKEYLENGTHPTR (SYSINDREMARKSPTR+256)

using namespace std;

class SysIndexEntry
{
	private: string _indexName; // Name of the index 64 bytes long
		 string _dbName; // Name of the database 64 bytes long
		 string _tableName; // Name of the table 64 bytes long
		 char _uniqueRule; // Whether the index is unique or not
		 // C - It is used to enforce uniqueness of a unique constraint
		 // D - No duplicates allowed
		 // U - Yes
		 // P - It is a primary index it enforces a referential constraint
		 // N - Yes and it is defined with UNIQUE WHERE NOT NULL
		 // R - Yes and it is used to enforce the uniqueness of a non-primary parent key
		 // G - Yes and it is used to enforce the uniqueness of a column defined as ROWID GENERATED BY DEFAULT
		 short _colCount; // The no. of columns in the key
		 short _fanOutNo; // Fan out for the index
		 int _indexPageID; // Root of the index
		 int _pageSize; // Page Size for the index
		 char _eraseRule; // Whether the datasets are erased when dropped N or Y - not used by us
		 char _closeRule; // Whether the datasets are candidates for closure when the limit on the no. of open data sets
		 // is reached - not used by us
		 string _remarks; // 256 bytes long - Remarks field...
		 int _avgKeyLength; // Average Key Length

		 static int _indID;
	
	public: SysIndexEntry()
		{
			_indexName = "Index Name";
			_dbName = "Database Name";
			_tableName = "Table Name";
			_uniqueRule = 'P';
			_colCount = 0;
			_fanOutNo = 0;
			_indexPageID = 0;
			_pageSize = 8192;
			_eraseRule = 'N';
			_closeRule = 'N';
			_remarks = "None";
			_avgKeyLength = 0;
		}

		~SysIndexEntry()
		{
			// Destructor for SysIndex entry....
		}

		string getIndexName();
		void setIndexName(string indexName);
		string getDBName();
		void setDBName(string dbName);
		string getTableName();
		void setTableName(string indexName);
		char getUniqueRule();
		void setUniqueRule(char uniqueRule);
		short getColCount();
		void setColCount(short colCount);
		short getFanOutNo();
		void setFanOutNo(short fanOutNo);
		int getIndexPageID();
		void setIndexPageID(int indexPageID);
		int getPageSize();
		void setPageSize(int pageSize);
		char getEraseRule();
		void setEraseRule(char eraseRule);
		char getCloseRule();
		void setCloseRule(char closeRule);
		string getRemarks();
		void setRemarks(string remarks);
		int getAvgKeyLength();
		void setAvgKeyLength(int avgKeyLength);

		int fillBuffer(char *buffer);
		int getDataBuffer(char *buffer);
};

class SysIndex
{
	private: int _pageID;
		 short _pagePriority;
		 int _nextSysIndexPage;
		 int _curSysIndexSize; // Check this is not required... This can be got by METADATASIZE + noe*TABLEENTRYSIZE
		 int _remSysIndexSize;
		 long _sysIndexEntryPointer;
		 int _noOfEntries;
		 int _pageSize;

	public: SysIndex()
		{
			_pagePriority = 50;
			_nextSysIndexPage = -1;
			_pageID = 3;
			_curSysIndexSize = SYSINDEXMETADATASIZE;
			_remSysIndexSize = SYSINDEXENTRYSPACE;
			_sysIndexEntryPointer = 0;
			_noOfEntries = 0;
		}

		SysIndex(int pageID)
		{
			_pagePriority = 50;
			_nextSysIndexPage = -1;
			_pageID = pageID;
			_curSysIndexSize = SYSINDEXMETADATASIZE;
			_remSysIndexSize = SYSINDEXENTRYSPACE;
			_sysIndexEntryPointer = 0;
			_noOfEntries = 0;
		}

		SysIndex(int pageID,int pageSize)
		{
			_pagePriority = 50;
			_pageSize = pageSize;
			_nextSysIndexPage = -1;
			_pageID = pageID;
			_curSysIndexSize = SYSINDEXMETADATASIZE;
			_remSysIndexSize = SYSINDEXENTRYSPACE;
			_sysIndexEntryPointer = 0;
			_noOfEntries = 0;
		}

		SysIndex(char *buffer)
		{
			memcpy(&_pageID,&buffer[PAGEIDPTR],sizeof(int));
			memcpy(&_pagePriority,&buffer[PAGEPRIPTR],sizeof(short));
			memcpy(&_nextSysIndexPage,&buffer[NEXTPTR],sizeof(int));
			memcpy(&_curSysIndexSize,&buffer[CURSYSINDSIZEPTR],sizeof(int));
			memcpy(&_remSysIndexSize,&buffer[REMSYSINDSIZEPTR],sizeof(int));
			memcpy(&_sysIndexEntryPointer,&buffer[SYSINDEXENTRYPTR],sizeof(long));
			memcpy(&_noOfEntries,&buffer[SYSINDNOEPTR],sizeof(int));
		}

		SysIndex(char *buffer,int pageSize)
		{
			_pageSize = pageSize;
			memcpy(&_pageID,&buffer[PAGEIDPTR],sizeof(int));
			memcpy(&_pagePriority,&buffer[PAGEPRIPTR],sizeof(short));
			memcpy(&_nextSysIndexPage,&buffer[NEXTPTR],sizeof(int));
			memcpy(&_curSysIndexSize,&buffer[CURSYSINDSIZEPTR],sizeof(int));
			memcpy(&_remSysIndexSize,&buffer[REMSYSINDSIZEPTR],sizeof(int));
			memcpy(&_sysIndexEntryPointer,&buffer[SYSINDEXENTRYPTR],sizeof(long));
			memcpy(&_noOfEntries,&buffer[SYSINDNOEPTR],sizeof(int));
		}

		~SysIndex()
		{
			// Destructor for SysIndex
		};

		int getPageID();
		void setPageID(int pageID);
		short getPagePriority();
		void setPagePriority(short pagePriority);
		int getNextSysIndexPage();
		void setNextSysIndexPage(int nextSysIndexPage);
		int getCurSysIndexSize();
		void setCurSysIndexSize(int curSysIndexSize);
		int getRemSysIndexSize();
		void setRemSysIndexSize(int remSysIndexSize);
		long getSysIndexEntryPointer();
		void setSysIndexEntryPointer(long sysIndexEntryPointer);
		int getNoOfEntries();
		void setNoOfEntries(int noOfEntries);
		int getPageSize();
		void setPageSize(int pageSize);

		bool checkEntryInsertion();
		int createNewSysIndexEntry(char *entryBuff,char *sysIndexBuff);
		int deleteSysIndexEntry(string indexName,char *sysIndexBuff);
		int searchSysIndexEntry(string indexName,char *sysIndexBuff);

		void writeSysIndexBuffer(char *buffer);
};
